<?php

namespace App\Model;


use App\Common\Model\MainBaseModel;
use App\Common\Model\ShopAccount;
use App\Common\Model\ShopUserStatus;
use App\Traits\ErrorTrait;

class Btree extends MainBaseModel
{
    use ErrorTrait;

    protected  $guarded = [];
    public $timestamps = false;

    /**
     * 获取用户所有子节点
     * @param int $uid
     * @return array|void
     */
    public function getAllChildren(int $uid) : array
    {
        $node = $this->where('uid', $uid)->first();
        if (!$node || ($node->lchild == 0 && $node->rchild == 0)) return [];

        $lowNodes = $this->select('uid', 'lchild', 'rchild')
            ->where([['btree_id', '=', $node->btree_id], ['level', '>', $node->level]])
            ->get()->toArray();
        // 如果为根节点,则下层所有节点为其子节点
        if ($uid == $node->btree_id) {
            return array_column($lowNodes, 'uid');
        }

        // 非根节点，查找其子节点
        $lrZone = $this->findLRZone($node->toArray(), $lowNodes);
        $children = array_merge($lrZone['lzone'], $lrZone['rzone']);
        return $children;

    }

    /**
     * 获取用户所有子节点数目
     * @param int $uid
     * @return int
     */
    public function getChildrenNum(int $uid) : int
    {
        $children = $this->getAllChildren($uid);
        return count($children);
    }

    /**
     * 获取左右区子节点
     * @param int $uid
     * @return array
     */
    public function getLRChildren(int $uid) : array
    {
        $node = $this->where('uid', $uid)->first();
        if (!$node || ($node->lchild == 0 && $node->rchild == 0)) return ['lzone' => [], 'rzone' => []];

        $lowNodes = $this->select('uid', 'lchild', 'rchild')
            ->where([['btree_id', '=', $node->btree_id], ['level', '>', $node->level]])
            ->get()->toArray();

        return $this->findLRZone($node->toArray(), $lowNodes);
    }

    /**
     * 获取左右子节点数目
     * @param int $uid
     * @return array
     */
    public function getLRChildrenNum(int $uid) : array
    {
        $lrZone = $this->getLRChildren($uid);
        return ['lnum' => count($lrZone['lzone']), 'rnum' => count($lrZone['rzone'])];
    }

    /**
     * 获取能够量碰的左右子节点
     * @param int $uid
     * @return array
     */
    public function getLimitLRChildren(int $uid) : array
    {
        $node = $this->where('uid', $uid)->first();
        if (!$node || ($node->lchild == 0 && $node->rchild == 0)) return ['lzone' => [], 'rzone' => []];
        // 获取能够量碰的层数
        $childNum = ShopAccount::where('p_uid', $uid)->where('level', '<>', 0)->count();
        $setting = (new Setting())->getTouchSet();
        $limit = 0;
        foreach ($setting['touch_layers_rules'] as $set) {
            if ($set['rec_num'] == $childNum) {
                $limit = $set['touch_layers'];
                break;
            } elseif ($set['rec_num'] < $childNum) {
                $limit = 99999;
            }
        }
        $limitLevel = $node->level + $limit;
        $lowNodes = $this->select('uid', 'lchild', 'rchild')
            ->where('btree_id', $node->btree_id)
            ->where('level', '>', $node->level)
            ->where('level', '<=', $limitLevel)
            ->get()->toArray();

        return $this->findLRZone($node->toArray(), $lowNodes);
    }

    /**
     * 查找用户左右区节点及相应接点人
     * @param array $pNode
     * @param array $nodes
     * @return array
     */
    public function findLRZone(array $pNode, array $nodes) : array
    {
        // 重组数组，键为用户id
        $keys = array_column($nodes, 'uid');
        $nodes = array_combine($keys, $nodes);
        // 初始化左区跟右区数组
        $lZone = [];
        $rZone = [];

        // 初始化左、右子节点节点集合
        $lCollege = [];
        $rCollege = [];
        if (isset($nodes[$pNode['lchild']])) {
            $lCollege[] = $nodes[$pNode['lchild']];
            unset($nodes[$pNode['lchild']]);
        }
        if (isset($nodes[$pNode['rchild']])) {
            $rCollege[] = $nodes[$pNode['rchild']];
            unset($nodes[$pNode['rchild']]);
        }

        while ($lCollege) {
            $node = array_shift($lCollege);
            $lZone[] = $node['uid'];
            if (isset($nodes[$node['lchild']])) {
                $lCollege[] = $nodes[$node['lchild']];
                unset($nodes[$node['lchild']]);
            }
            if (isset($nodes[$node['rchild']])) {
                $lCollege[] = $nodes[$node['rchild']];
                unset($nodes[$node['rchild']]);
            }
        }

        while ($rCollege) {
            $node = array_shift($rCollege);
            $rZone[] = $node['uid'];
            if (isset($nodes[$node['lchild']])) {
                $rCollege[] = $nodes[$node['lchild']];
                unset($nodes[$node['lchild']]);
            }
            if (isset($nodes[$node['rchild']])) {
                $rCollege[] = $nodes[$node['rchild']];
                unset($nodes[$node['rchild']]);
            }
        }
        return ['lzone' => $lZone, 'rzone' => $rZone];

    }

    /**
     * 获取用户左区或者右区子节点有空白的用户id集合
     * @param int $uid
     * @param string $zone   'l'为左区， 'r为右区'
     * @return mixed
     */
    public function getLZoneNull(int $uid)
    {
        $res = $this->getAllChildren($uid);
        $res[] = $uid;
        return $this->whereIn('uid', $res)->where(function ($query) {
                    $query->where('lchild', 0)->orWhere('rchild', 0);
                })->pluck('uid')->toArray();
    }


    /**
     * @param $uid
     * @param int $linkId
     * @param string
     * @return bool $zone  'l'代表左区， 'r'代表右区
     */
    public function addNode($uid, $linkId = 0, $zone)
    {
        $has = $this->where('uid', $uid)->count();
        if ($has > 0) {
            $this->error = '该用户已被分配';
            return false;
        }
        $active = ShopUserStatus::where('uid', $uid)->value('vip_status');
        if ($active != ShopUserStatus::STATUS_SUCCESS) { // 已验证时
            $this->error = '该用户未激活';
            return false;
        }
        $this->uid = $uid;
        $this->lchild = 0;
        $this->rchild = 0;
        $this->create_time = time();
        if ($linkId == 0) {
            $this->btree_id = $uid;
            $this->level = 1;
            $this->link_id = 0;
            $this->save();
            return true;
        }
        $linkNode = $this->where('uid', $linkId)->where(function ($query) {
            $query->where('lchild', 0)->orWhere('rchild', 0);
        })->first();
        if (!$linkNode) {
            $this->error = '该用户子节点已满';
            return false;
        }
        if ($zone == 'l') {
            if ($linkNode->lchild != 0) {
                $this->error = '该用户左子节点已满';
                return false;
            }
            $linkNode->lchild = $uid;
        } elseif ($zone == 'r') {
            if ($linkNode->rchild != 0) {
                $this->error = '该用户右子节点已满';
                return false;
            }
            $linkNode->rchild = $uid;
        } else {
            $this->error = '请选择左右区';
            return false;
        }
        $linkNode->save();
        $this->btree_id = $linkNode->btree_id;
        $this->level = $linkNode->level + 1;
        $this->link_id = $linkId;
        $this->save();
        return true;

    }

    /**
     * 查找用户所有接点人，并计算接点人在多少层
     * @param int $uid
     * @return array
     */
    public function findAllLinkNode(int $uid)
    {
        $node =$this->where('uid', $uid)->first();
        if (!$node || $node->link_id == 0) return [];

        $upNodes = $this->leftJoin('shop_accounts', 'btrees.uid', '=', 'shop_accounts.uid')
            ->where('btree_id', $node->btree_id)->where('btrees.level', '<', $node->level)
            ->select('btrees.uid', 'shop_accounts.level', 'link_id', 'lchild', 'rchild', 'lsale', 'rsale')
            ->get()->toArray();

        $keys = array_column($upNodes, 'uid');
        $upNodes = array_combine($keys, $upNodes);
        $node = $node->toArray();
        $linkNodes = [];
        $upLevel = 0;
        $index = $node['link_id'];
        while (isset($upNodes[$index])) {
            ++$upLevel;
            $upNodes[$index]['up_layers'] = $upLevel;
            $linkNodes[] = $upNodes[$index];
            $index = $upNodes[$index]['link_id'];
        }
        return $linkNodes;

    }

    /*
     * 根据用户的ID去查找自己的接点人
     */
    public function findOwerLinkNode(int $uid)
    {
        $link_id = self::where(['uid'=>$uid])->value('link_id');
        //根据这个$link_id去accounts表里面查信息;
        $shopAccount = new ShopAccount();
        return $shopAccount->getSingle($link_id);
    }
}
